home *** CD-ROM | disk | FTP | other *** search
Text File | 1991-02-07 | 8.4 KB | 267 lines | [TEXT/MPS ] |
- {-------------------------------------------------------------------------------
- #
- # Apple Macintosh Developer Technical Support
- #
- # Interfaces for the emergency memory routines
- #
- # Program: ProcDoggie
- # File: UEmergMem.inc1.p - Pascal Implementation
- #
- # by: Forrest Tanaka
- #
- # Copyright © 1988-1991 Apple Computer, Inc.
- # All rights reserved.
- #
- -------------------------------------------------------------------------------}
- {[j=20/57/1$] Pasmat Options}
- {$R-}
-
-
- (*******************************************************************************
- * Constants
- *******************************************************************************)
-
- CONST
- kEmergMemSize = 32768; {Number of bytes of emergency memory to allocate}
- kMemoryMargin = 32768; {Minimum amount of free memory I allow in the heap}
-
-
- (*******************************************************************************
- * Global Variables
- *******************************************************************************)
-
- VAR
- gEmergMem: Handle; {Handle to block of emergency memory}
-
-
- {$S Main}
- (*******************************************************************************
- * Private: AppGrowZone - Custom grow-zone procedure
- *
- * This is a very basic grow zone procedure. My application keeps a reserve
- * handle of memory in case the Memory Manager gets a request for some memory
- * that is not available in my heap. If memory were to get tight (<32k), the
- * Toolbox will crash the system. This grow-zone proc tries to thwart that
- * possibility by releasing the 32K block of emergency memory if it hasn’t been
- * released already and if the amount of memory requested is less than 32K.
- * Hopefully, that’s enough to satisfy the memory request.
- *
- * There are three conditions in which the emergency memory isn’t freed. If the
- * emergency memory is already free, obviously there isn’t much that can be done.
- * If the emergency memory is equal to GZSaveHnd, then it was the reallocation of
- * emergency memory that caused this grow-zone proc to be called. So it doesn’t
- * make much sense to free it in that case. If the size of the memory request is
- * more than the size of emergency memory, then I don’t bother to free emergency
- * memory because I assume that the toolbox handles such huge requests for memory
- * properly. Warning: that isn’t always a good assumption, but that’s not my
- * fault.
- *
- * WARNING: Register A5 might not be valid when grow-zone procedures
- * are called. Read Technical Note #136 and 208.
- *
- * The "cbNeeded" parameter is the number of bytes that the Memory Manager needs
- * to fulfill the memory request it had received. The number of bytes actually
- * freed by AppGrowZone is returned.
- *******************************************************************************)
-
-
- FUNCTION AppGrowZone (cbNeeded: Size): LongInt;
-
- VAR
- theA5: LongInt; {Value of A5 when AppGrowZone is called}
-
- BEGIN
- (* Remember the current value of A5 *)
- theA5 := SetCurrentA5;
-
- (* Free emergency memory if possible *)
- IF (gEmergMem^ <> NIL) & (gEmergMem <> GZSaveHnd) & (cbNeeded <=
- kEmergMemSize) THEN
- BEGIN
- EmptyHandle (gEmergMem);
- AppGrowZone := kEmergMemSize
- END
- ELSE
- AppGrowZone := 0;
-
- (* Restore A5 *)
- theA5 := SetA5 (theA5)
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: ConnectAppGZ
- *
- * It’s pretty self-explanatory.
- *******************************************************************************)
-
- PROCEDURE ConnectAppGZ;
-
- BEGIN
- SetGrowZone (@AppGrowZone)
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: DisconnectAppGZ
- *
- * It’s pretty self-explanatory.
- *******************************************************************************)
-
- PROCEDURE DisconnectAppGZ;
-
- BEGIN
- SetGrowZone (NIL)
- END;
-
-
- {$S %A5Init}
- (*******************************************************************************
- * Public: InitEmergMem
- *
- * It’s pretty self-explanatory.
- *******************************************************************************)
-
- PROCEDURE InitEmergMem;
-
- BEGIN
- gEmergMem := NewHandle (kEmergMemSize);
- ConnectAppGZ
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: NoEmergMem
- *
- * We check on the handle and the master pointer of gEmergMem to see if the
- * emergency memory block has been emptied by AppGrowZone, or was never allocated
- * in the first place.
- *******************************************************************************)
-
- FUNCTION NoEmergMem: Boolean;
-
- BEGIN
- (* Empty handle means no emergency memory *)
- NoEmergMem := (gEmergMem = NIL) | (gEmergMem^ = NIL)
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: RecoverEmergMem
- *
- * Not much to describe.
- *******************************************************************************)
-
- PROCEDURE RecoverEmergMem;
-
- BEGIN
- ReallocHandle (gEmergMem, kEmergMemSize);
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: FailLowMemory
- *
- * PurgeSpace is used to determine how much free memory there’d be in the heap if
- * all purgeable blocks were purged. If this amount is less than the amount
- * needed, or if there isn’t any emergency memory, TRUE is returned.
- *******************************************************************************)
-
- FUNCTION FailLowMemory (memRequest: LongInt): Boolean;
-
- VAR
- total: LongInt; {Total amount of free memory if heap was purged}
- contig: LongInt; {Max amount of free contiguous memory if heap was purged}
-
- BEGIN
- PurgeSpace ((*<*)total, (*<*)contig);
- FailLowMemory := (total < (memRequest + kMemoryMargin)) | NoEmergMem
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: NewHandleMargin
- *
- * I don’t call SysError with an ID 25 if there isn’t enough memory to satisfy
- * the request, so there isn’t much reason to use the grow-zone proc. So, I
- * disconnect the grow-zone proc temporarily just before I allocate the memory.
- *******************************************************************************)
-
- FUNCTION NewHandleMargin (requestedSize: Size;
- appHeapAlloc: Boolean;
- clearMem: Boolean): Handle;
-
- VAR
- total: LongInt; {Total free bytes after a theoretical heap purge/compaction}
- contig: LongInt; {Largest contig free block from theoretical heap purge/compaction}
-
- BEGIN
- IF FailLowMemory (requestedSize) THEN
- NewHandleMargin := NIL
- ELSE
- BEGIN
- (* We handle memFullErr properly, so don’t need grow-zone proc *)
- DisconnectAppGZ;
-
- (* Allocate the memory with the requested options *)
- IF (NOT appHeapAlloc) AND clearMem THEN
- NewHandleMargin := NewHandleSysClear (requestedSize)
- ELSE IF (NOT appHeapAlloc) THEN
- NewHandleMargin := NewHandleSys (requestedSize)
- ELSE IF clearMem THEN
- NewHandleMargin := NewHandleClear (requestedSize)
- ELSE
- NewHandleMargin := NewHandle (requestedSize);
-
- (* Connect up the grow-zone proc again *)
- ConnectAppGZ
- END
- END;
-
-
- {$S Main}
- (*******************************************************************************
- * Public: NewPtrMargin
- *
- * I don’t call SysError with an ID 25 if there isn’t enough memory to satisfy
- * the request, so there isn’t much reason to use the grow-zone proc. So, I
- * disconnect the grow-zone proc temporarily just before I allocate the memory.
- *******************************************************************************)
-
- FUNCTION NewPtrMargin (requestedSize: Size;
- appHeapAlloc: Boolean;
- clearMem: Boolean): Ptr;
-
- VAR
- total: LongInt; {Total free bytes after a theoretical heap purge/compaction}
- contig: LongInt; {Largest contig free block from theoretical heap purge/compaction}
-
- BEGIN
- IF FailLowMemory (requestedSize) THEN
- NewPtrMargin := NIL
- ELSE
- BEGIN
- (* We handle memFullErr properly, so don’t need grow-zone proc *)
- DisconnectAppGZ;
-
- (* Allocate the memory with the requested options *)
- IF (NOT appHeapAlloc) AND clearMem THEN
- NewPtrMargin := NewPtrSysClear (requestedSize)
- ELSE IF NOT appHeapAlloc THEN
- NewPtrMargin := NewPtrSys (requestedSize)
- ELSE IF clearMem THEN
- NewPtrMargin := NewPtrClear (requestedSize)
- ELSE
- NewPtrMargin := NewPtr (requestedSize);
-
- (* Connect up the grow-zone proc again *)
- ConnectAppGZ
- END
- END;
-